 /*
  *@(#)SpiderCtlImpl.java		8 Sept. 2000
  *
  * Copyright: MetaPlus Inc & Inquiry Management Systems Ltd.  2000
  *
  * This software is the proprietary information of MetaPlus Inc & 
  * Inquiry Management Systems Ltd.  
  * Use is subject to license terms.
  */
package com.ims.iaa;

import java.rmi.RemoteException;
import java.util.*;
import java.rmi.server.*;

/**
  * The <code>SpiderCtlImpl</code> object represents the "Spider Control Center"
  * service. It implementes the <code>SpiderCtl</code> remote interface to
  * provides services for other objects. There should only be one instance in
  * the application to centrally control all the spiders.
  *
  * @see SpiderCtl
  *
  * @author Anthony Zhang
  *
  * @version 1.00, 25 Sept. 2000
  *
  */
public class SpiderCtlImpl extends UnicastRemoteObject implements SpiderCtl {
	 
  /** Ad collectors available for processing requests    */	
  private Vector adSpiders;
  
  private RequestCtl reqCenter;
  
  private String hostName = "localhost";
  private int registryPort = 1099;  
  private int spiderCount = 0; 

  private Thread eventThread;
  private HashMap m_clientNameMap;

  private void setEventThread() {
	  eventThread = new IaaThread("SpiderCtrlEvent")  {
    		public void run()  {
			if ( reqCenter == null) {
				reqCenter = IaaUtil.getRequestCenter(hostName,registryPort);	
				if ( reqCenter == null) return;
  			}
		
		 	log("notify Request Control Center about free spider joined." );	
					
			try {
				reqCenter.raiseDispatchEvent();
			} catch (Exception e) {
				log("communication with Request Control Center error:" + e );
			}
	  	} // end of run()
	  } ; //end of anonymous class
  }
  /** 
    *  
    */
  public SpiderCtlImpl(int serverPort)      throws java.rmi.RemoteException {
  	registryPort = ((serverPort == 0)? registryPort: serverPort);
  	//++Add by ShengMeng Bai at 2004-10-04
  	hostName = IaaDebug.ServerHost;
  	//--Add by ShengMeng Bai at 2004-10-04
  	adSpiders = new Vector();
  	
  	m_clientNameMap = new HashMap();
  }
  /**
   * Register a client machine in Spider Control Center, 
   * and get the current registered index which register by the same machine.
   * @param sMachineName
   * @return the register index.
   */
  public int registerClient(String sMachineName){
    Integer count = (Integer)m_clientNameMap.get(sMachineName);
    int iRet = 1;
    if(count != null){
    	iRet = count.intValue() + 1;
    }
	m_clientNameMap.put(sMachineName, new Integer(iRet));
    return iRet;
  }

  /** 
    *  Gets ad collector from the SpiderCtl
    */
  protected synchronized AdSpider getAdSpider() {
  	 
	 AdSpider adSpider = null;
  
     if(IaaDebug.Debug) log("get one spider from the Spider Queue" );
	 					
	 if( !adSpiders.isEmpty()) {
	 	adSpider = (AdSpider)adSpiders.firstElement();
	 }
	 try  {
		 removeAdSpider(adSpider);
	 } catch (Exception e)  {
	 	//Add by ShengMeng Bai at 2004-11-09
	 	adSpider = null;
	 	if(IaaDebug.Debug)log(e.toString() );log("removeAdSpidere Exception:"+ e.toString() );	
	 }
	 return adSpider;
  }  	
  
  
  /** 
    *  Registers a free AdSpider to the SpiderCtl
    *
    *  @param adSpider The AdSpider which is free to proecess  ad track request. 
    */
  public synchronized void registerAdSpider( AdSpider adSpider) 
	throws RemoteException {
	
		addAdSpider(adSpider);
		raiseSpiderEvent();	

  }  	


  private void addAdSpider( AdSpider adSpider) 
	throws RemoteException {
	
		if(IaaDebug.Debug) 
				log("add spider [" + adSpider.getSpiderName() + "] to the Spider Queue" );	
				
		if( !adSpiders.contains(adSpider)) {
			adSpiders.addElement(adSpider); 	
		}
		
		//++delete by ShengMengBai at 2005-02-28
		//cause spide name change.
		/*
		//modified by Anthony Zhang 20 Nov 2000, the spiderCount will not increase if the
		// spider specified by reference adSpider is an old spider
		try  {
			//if it is a new spider, server will assign a new name to the spider
			if (adSpider.isNewSpider())  {
				spiderCount++;
				//adSpider.setSpiderName(spiderCount);
				adSpider.setSpiderName();
			}
		} catch (Exception e)  {
			log("error set spider name to[" + adSpider.getSpiderName() + "]");
		}*/
		//--delete by ShengMengBai at 2005-02-28
  } 
  	
  /** 
    *  Removes a busy AdSpider from the SpiderCtl
    *
    *  @param adSpider The AdSpider which is assign with ad track request 
	*  and become busy. 
    */
  public synchronized void removeAdSpider( AdSpider adSpider) 
	throws RemoteException {
	
		if(IaaDebug.Debug) 
				log("remove ["+ adSpider.getSpiderName() +"] from the Spider Queue" );		
				
		adSpiders.removeElement(adSpider);
  }  	
  
  /** 
    *  
    */
  protected void raiseSpiderEvent(){
	  if(IaaDebug.Debug)log("Raise spider event." );		
	  if(eventThread==null)setEventThread();
	  IaaDebug.assert_6(eventThread!=null);
	  if(eventThread.isAlive()) {
		if(IaaDebug.Debug)log("eventThread still alive" );		
	  } else {
		if(IaaDebug.Debug)log("eventThread dead" );
		setEventThread();
		eventThread.start(); 
	  }
  }
  

  /** 
    *  
    */
  public boolean isReady() {
  
  		boolean empty_flag = adSpiders.isEmpty();
  
	 	if (IaaDebug.Debug) {
			if (empty_flag)   {  
	  			log("check -- No spider available in Spider Queue" );	
			} else  {
	  			log("check -- Spider available in Spider Queue" );				
			}	
	 	}
		
  		return (!empty_flag);
		
  }
  
  public boolean processRequest(AdTrackRequest adReq) {
  
  	 	if(IaaDebug.Debug) 
  			log("receive the request from the Ads Request Control Center" );	

  	  	if( isReady() ) {
  	  			AdSpider adSpider = getAdSpider();
				
				if ( adSpider != null)  {
					try {
				 		if(IaaDebug.Debug) 
  							log("try to notify the spider [" + adSpider.getSpiderName() + "]");				

						if (!adSpider.notifyPerform(adReq))  {
							if(IaaDebug.Debug) 
  								log("error when notify the spider [" + adSpider.getSpiderName() + "]");						
							registerAdSpider(adSpider);	
						} else  {
							if(IaaDebug.Debug) 
  								log( "notify the spider [" + adSpider.getSpiderName() + "] successfully");						
						}
						return true;
					} catch (Exception e) {
						if(IaaDebug.Debug) log("error when notified the spider " + e);
						IaaUtil.printStackTrace(e);
						return false;
					}
  	  			}else{
  	  				log( "No spider in SpiderCenter!");
  	  				return false;
  	  			}
  	  	} 
		
	 	if(IaaDebug.Debug) log("spider not available in queue." );
		return false;

  }
  
  private void log(String s)  {
	  	IaaUtil.log("[Spider Control Center] " + s);
  }
  
}
